import RPi.GPIO as GPIO
import paho.mqtt.client as mqtt
import gpiozero as gz
import time

# dj:djon
# DHT11
# HX711

#DHTPIN = 4
DHTPIN = 7

#GPIO.setmode(GPIO.BCM)
GPIO.setmode(GPIO.BOARD)

MAX_UNCHANGE_COUNT = 100

STATE_INIT_PULL_DOWN = 1
STATE_INIT_PULL_UP = 2
STATE_DATA_FIRST_PULL_DOWN = 3
STATE_DATA_PULL_UP = 4
STATE_DATA_PULL_DOWN = 5

def read_dht11_dat():
	GPIO.setup(DHTPIN, GPIO.OUT)
	GPIO.output(DHTPIN, GPIO.HIGH)
	time.sleep(0.05)
	GPIO.output(DHTPIN, GPIO.LOW)
	time.sleep(0.02)
	GPIO.setup(DHTPIN, GPIO.IN, GPIO.PUD_UP)

	unchanged_count = 0
	last = -1
	data = []
	while True:
		current = GPIO.input(DHTPIN)
		data.append(current)
		if last != current:
			unchanged_count = 0
			last = current
		else:
			unchanged_count += 1
			if unchanged_count > MAX_UNCHANGE_COUNT:
				break

	state = STATE_INIT_PULL_DOWN

	lengths = []
	current_length = 0

	for current in data:
		current_length += 1

		if state == STATE_INIT_PULL_DOWN:
			if current == GPIO.LOW:
				state = STATE_INIT_PULL_UP
			else:
				continue
		if state == STATE_INIT_PULL_UP:
			if current == GPIO.HIGH:
				state = STATE_DATA_FIRST_PULL_DOWN
			else:
				continue
		if state == STATE_DATA_FIRST_PULL_DOWN:
			if current == GPIO.LOW:
				state = STATE_DATA_PULL_UP
			else:
				continue
		if state == STATE_DATA_PULL_UP:
			if current == GPIO.HIGH:
				current_length = 0
				state = STATE_DATA_PULL_DOWN
			else:
				continue
		if state == STATE_DATA_PULL_DOWN:
			if current == GPIO.LOW:
				lengths.append(current_length)
				state = STATE_DATA_PULL_UP
			else:
				continue
	if len(lengths) != 40:
		# print("Data not good, skip")
		return False

	shortest_pull_up = min(lengths)
	longest_pull_up = max(lengths)
	halfway = (longest_pull_up + shortest_pull_up) / 2
	bits = []
	the_bytes = []
	byte = 0

	for length in lengths:
		bit = 0
		if length > halfway:
			bit = 1
		bits.append(bit)
	# print("bits: %s, length: %d" % (bits, len(bits)))
	for i in range(0, len(bits)):
		byte = byte << 1
		if (bits[i]):
			byte = byte | 1
		else:
			byte = byte | 0
		if ((i + 1) % 8 == 0):
			the_bytes.append(byte)
			byte = 0
	# print(the_bytes)
	checksum = (the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3]) & 0xFF
	if the_bytes[4] != checksum:
		# print("Data not good, skip")
		return False

	return the_bytes[0], the_bytes[2]

def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    client.subscribe("dj")

# 回调函数，当收到消息时，触发该函数
def on_message(client, userdata, msg):
    # print(f"{msg.topic} {msg.payload}")
    # dj
    s=gz.Servo(2,min_pulse_width=0.5/1000,max_pulse_width=2.5/1000,frame_width=20.0/1000)
    if(msg.payload.decode('gbk')=='djon'):
        s.min()
        time.sleep(1)
        s.max()
        time.sleep(1)

class Hx711():
    def setup(self):
        self.SCK = 11    # 物理引脚第11号，时钟
        self.DT = 13     #物理引脚第13号，数据
        self.flag=1      #用于首次读数校准
        self.initweight=0	#毛皮
        self.weight=0		#测重
        self.delay=0.09		#延迟时间
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
        GPIO.setup(self.SCK, GPIO.OUT)      # Set pin's mode is output
        GPIO.setup(self.DT, GPIO.IN)
        GPIO.setup(self.DT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
            
    def start(self):
        GPIO.output(self.SCK,0)
        if GPIO.input(self.SCK):
            time.sleep(self.delay)
        value=0
        while GPIO.input(self.DT):
            time.sleep(self.delay)
        #循环24次读取数据
        for i in range(24):
            GPIO.output(self.SCK,1)
            if(0==GPIO.input(self.SCK)):
                time.sleep(self.delay)
            value=value<<1		#左移一位，相当于乘2，二进制转十进制
            GPIO.output(self.SCK,0)
            if GPIO.input(self.SCK):
                time.sleep(self.delay)
            if GPIO.input(self.DT)==1:
                value+=1
        GPIO.output(self.SCK,1)
        GPIO.output(self.SCK,0)
        value=int(value/502)		#1905为我传感器的特性值，不同传感器值不同。可先注释此步骤，再去测一物体A得到一个值X,而后用X除以A的真实值即可确定特性值
        if self.flag==1:			#第一次读数为毛皮
            self.flag=0
            self.initweight=value        #初始值
        else:
            self.weight=abs(value-self.initweight)	#当前值减毛皮得测量到的重量
            #print(self.weight)
            return self.weight

def main():
    send=Hx711()
    send.setup()
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect("sunshinego.online", 1883, 60)
    
    while True:
        result = read_dht11_dat()
        weight = send.start()
        if weight:
            str = "weight: %s" % weight
            client.publish('HX711', payload=str, qos=0, retain=False)
            # print("weight: %s" % weight)
        if result:
            humidity, temperature = result
            str = "humidity: %s %%,  Temperature: %s C`" % (humidity, temperature)
            client.publish('DHT11', payload=str, qos=0, retain=False)
            # print("humidity: %s %%,  Temperature: %s C`" % (humidity, temperature))
        client.loop_start()
        time.sleep(1)

def destroy():
	GPIO.cleanup()

if __name__ == '__main__':
	try:
		main()
	except KeyboardInterrupt:
		destroy() 

